home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / base / netkit-b.07a / netkit-b / NetKit-B-0.07A / rexecd / rexecd.c < prev   
Encoding:
C/C++ Source or Header  |  1996-07-26  |  10.7 KB  |  424 lines

  1. /*
  2.  * Copyright (c) 1983 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. char copyright[] =
  35.   "@(#) Copyright (c) 1983 The Regents of the University of California.\n"
  36.   "All rights reserved.\n";
  37.  
  38. /*
  39.  * From: @(#)rexecd.c    5.12 (Berkeley) 2/25/91
  40.  */
  41. char rcsid[] = 
  42.   "$Id: rexecd.c,v 1.10 1996/07/26 04:51:44 dholland Exp $";
  43.  
  44.  
  45. #include <sys/param.h>
  46. #include <sys/ioctl.h>
  47. #include <sys/socket.h>
  48. #include <sys/time.h>
  49. #include <netinet/in.h>
  50. #include <signal.h>
  51. #include <netdb.h>
  52. #include <pwd.h>
  53. #include <errno.h>
  54. #include <syslog.h>
  55. #include <unistd.h>
  56. #include <stdio.h>
  57. #include <stdlib.h>
  58. #include <string.h>
  59. #include <paths.h>
  60. #include <grp.h>
  61.  
  62. #ifdef USE_PAM
  63. #include <security/pam_appl.h>
  64. #endif
  65.  
  66. #define _PATH_FTPUSERS        "/etc/ftpusers"
  67.  
  68. #ifdef TCP_WRAPPER
  69. #include <syslog.h>
  70. #include "log_tcp.h"
  71. struct from_host from_host;
  72. #endif
  73.  
  74. int allow_severity = LOG_INFO;
  75. int deny_severity = LOG_WARNING;
  76.  
  77.  
  78. /*
  79.  * remote execute server:
  80.  *    username\0
  81.  *    password\0
  82.  *    command\0
  83.  *    data
  84.  */
  85.  
  86. static void fatal(const char *);
  87. static void doit(int f, struct sockaddr_in *fromp);
  88. static void getstr(char *buf, int cnt, const char *err);
  89.  
  90. static const char *remote = NULL;
  91.  
  92. int
  93. main(int argc, char **argv)
  94. {
  95.     struct sockaddr_in from;
  96.     int fromlen;
  97.  
  98.     fromlen = sizeof(from);
  99.     if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
  100.         fprintf(stderr, "rexecd: getpeername: %s\n", strerror(errno));
  101.         return 1;
  102.     }
  103.  
  104.     openlog(argv[0], LOG_PID, LOG_DAEMON);
  105.  
  106. #ifdef    TCP_WRAPPER
  107.     /* Find out and report the remote host name. */
  108.     /* I don't think this works. -- dholland */
  109.     if (fromhost(&from_host) < 0 || !hosts_access(argv[0], &from_host))
  110.         refuse(&from_host);
  111.     remote = hosts_info(&from_host);
  112. #else
  113.     {
  114.     struct hostent *h = gethostbyaddr((const char *)&from.sin_addr,
  115.                       sizeof(struct in_addr),
  116.                       AF_INET);
  117.     if (!h || !h->h_name) {
  118.         write(0, "\1Where are you?\n", 16);
  119.         return 1;
  120.     }
  121.     /* Be advised that this may be utter nonsense. */
  122.     remote = h->h_name;
  123.     }
  124. #endif
  125.     syslog(allow_severity, "connect from %.128s", remote);
  126.     doit(0, &from);
  127.     return 0;
  128. }
  129.  
  130. char    username[20] = "USER=";
  131. char    homedir[64] = "HOME=";
  132. char    shell[64] = "SHELL=";
  133. char    path[sizeof(_PATH_DEFPATH) + sizeof("PATH=")] = "PATH=";
  134. char    *envinit[] =
  135.         {homedir, shell, path, username, 0};
  136. char    **myenviron;
  137.  
  138. #ifdef USE_PAM
  139. static char *PAM_username;
  140. static char *PAM_password;
  141.  
  142. static int PAM_conv (int num_msg,
  143.                      const struct pam_message **msg,
  144.                      struct pam_response **resp,
  145.                      void *appdata_ptr) {
  146.   int count = 0, replies = 0;
  147.   struct pam_response *reply = NULL;
  148.   int size = sizeof(struct pam_response);
  149.  
  150.   #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \
  151.   if (!reply) return PAM_CONV_ERR; \
  152.   size += sizeof(struct pam_response)
  153.   #define COPY_STRING(s) (s) ? strdup(s) : NULL
  154.  
  155.   for (count = 0; count < num_msg; count++) {
  156.     switch (msg[count]->msg_style) {
  157.       case PAM_PROMPT_ECHO_ON:
  158.         GET_MEM;
  159.         reply[replies].resp_retcode = PAM_SUCCESS;
  160.         reply[replies++].resp = COPY_STRING(PAM_username);
  161.           /* PAM frees resp */
  162.         break;
  163.       case PAM_PROMPT_ECHO_OFF:
  164.         GET_MEM;
  165.         reply[replies].resp_retcode = PAM_SUCCESS;
  166.         reply[replies++].resp = COPY_STRING(PAM_password);
  167.           /* PAM frees resp */
  168.         break;
  169.       case PAM_TEXT_INFO:
  170.         /* ignore it... */
  171.         break;
  172.       case PAM_ERROR_MSG:
  173.       default:
  174.         /* Must be an error of some sort... */
  175.         free (reply);
  176.         return PAM_CONV_ERR;
  177.     }
  178.   }
  179.   if (reply) *resp = reply;
  180.   return PAM_SUCCESS;
  181. }
  182.  
  183. static struct pam_conv PAM_conversation = {
  184.     &PAM_conv,
  185.     NULL
  186. };
  187. #endif /* USE_PAM */
  188.  
  189.  
  190. static void
  191. doit(int f, struct sockaddr_in *fromp)
  192. {
  193.     char cmdbuf[ARG_MAX+1], *cp, *namep;
  194.     char user[16], pass[16];
  195.     struct passwd *pwd;
  196.     int s = -1;
  197.     u_short port;
  198.     int pv[2], pid, ready, readfrom, cc;
  199.     char buf[BUFSIZ], sig;
  200. #ifdef RESTRICT_FTP
  201.     FILE *fp;
  202. #endif
  203. #ifdef USE_PAM
  204.        pam_handle_t *pamh;
  205.        int pam_error;
  206. #endif
  207.  
  208.     signal(SIGINT, SIG_DFL);
  209.     signal(SIGQUIT, SIG_DFL);
  210.     signal(SIGTERM, SIG_DFL);
  211. #ifdef DEBUG
  212.     { int t = open(_PATH_TTY, 2);
  213.       if (t >= 0) {
  214.         ioctl(t, TIOCNOTTY, NULL);
  215.         close(t);
  216.       }
  217.     }
  218. #endif
  219.  
  220.     dup2(f, 0);
  221.     dup2(f, 1);
  222.     dup2(f, 2);
  223.     alarm(60);
  224.     port = 0;
  225.     for (;;) {
  226.         char c;
  227.         if (read(f, &c, 1) != 1)
  228.             exit(1);
  229.         if (c == 0)
  230.             break;
  231.         port = port * 10 + c - '0';
  232.     }
  233.     alarm(0);
  234.     if (port != 0) {
  235.         s = socket(AF_INET, SOCK_STREAM, 0);
  236.         if (s < 0)
  237.             exit(1);
  238.  
  239. #if 0 /* this shouldn't be necessary */
  240.         struct    sockaddr_in asin = { AF_INET };
  241.         if (bind(s, (struct sockaddr *)&asin, sizeof (asin)) < 0)
  242.             exit(1);
  243. #endif
  244.         alarm(60);
  245.         fromp->sin_port = htons(port);
  246.         if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0)
  247.             exit(1);
  248.         alarm(0);
  249.     }
  250.     getstr(user, sizeof(user), "username too long\n");
  251.     getstr(pass, sizeof(pass), "password too long\n");
  252.     getstr(cmdbuf, sizeof(cmdbuf), "command too long\n");
  253. #ifdef USE_PAM
  254.        #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
  255.                pam_end(pamh, pam_error); exit(1); \
  256.        }
  257.        PAM_username = user;
  258.        PAM_password = pass;
  259.        pam_error = pam_start("rexec", PAM_username, &PAM_conversation,&pamh);
  260.        PAM_BAIL;
  261.        pam_error = pam_authenticate(pamh, 0);
  262.        PAM_BAIL;
  263.        pam_error = pam_acct_mgmt(pamh, 0);
  264.        PAM_BAIL;
  265.        pam_error = pam_setcred(pamh, PAM_CRED_ESTABLISH);
  266.        PAM_BAIL;
  267.        pam_end(pamh, PAM_SUCCESS);
  268.        /* If this point is reached, the user has been authenticated. */
  269.        setpwent();
  270.        pwd = getpwnam(user);
  271.        endpwent();
  272. #else /* !USE_PAM */
  273.        /* All of the following issues are dealt with in the PAM configuration
  274.           file, so put all authentication/priviledge checks before the
  275.           corresponding #endif below. */
  276.  
  277.     setpwent();
  278.     pwd = getpwnam(user);
  279.     if (pwd == NULL) {
  280.         /* Log failed attempts. */
  281.         syslog(LOG_ERR, "LOGIN FAILURE from %.128s, %s", remote, user);
  282.         fatal("Login incorrect.\n");
  283.     }
  284.     endpwent();
  285.     if (*pwd->pw_passwd != '\0') {
  286.         namep = crypt(pass, pwd->pw_passwd);
  287.         if (strcmp(namep, pwd->pw_passwd)) {
  288.             /* Log failed attempts. */
  289.             syslog(LOG_ERR, "LOGIN FAILURE from %.128s, %s",
  290.                    remote, user);
  291.             fatal("Login incorrect.\n");
  292.         }
  293.     }
  294.     /* Disallow access to root account. */
  295.     if (pwd->pw_uid == 0) {
  296.         syslog(LOG_ERR, "%s LOGIN REFUSED from %.128s", user, remote);
  297.         fatal("Login incorrect.\n");
  298.     }
  299. #ifdef RESTRICT_FTP
  300.     /* Disallow access to accounts in /etc/ftpusers. */
  301.     fp = fopen(_PATH_FTPUSERS, "r");
  302.     if (fp != NULL) {
  303.         while (fgets(buf, sizeof(buf), fp) != NULL) {
  304.         if ((cp = strchr(buf, '\n')) != NULL)
  305.             *cp = '\0';
  306.         if (strcmp(buf, pwd->pw_name) == 0) {
  307.             syslog(LOG_ERR, "%s LOGIN REFUSED from %.128s",
  308.                    user, remote);
  309.             fatal("Login incorrect.\n");
  310.         }
  311.         }
  312.         fclose(fp);
  313.     }
  314.     else syslog(LOG_ERR, "cannot open /etc/ftpusers");
  315. #endif
  316. #endif /* !USE_PAM */
  317.  
  318.     /* Log successful attempts. */
  319.     syslog(LOG_INFO, "login from %.128s as %s", remote, user);
  320.  
  321.     if (chdir(pwd->pw_dir) < 0) {
  322.         fatal("No remote directory.\n");
  323.     }
  324.     write(2, "\0", 1);
  325.     if (port) {
  326.         if (pipe(pv)) fatal("Try again later.\n");
  327.         if (s>=CHAR_BIT*sizeof(readfrom) || 
  328.             pv[0]>=CHAR_BIT*sizeof(readfrom) || 
  329.             pv[1]>=CHAR_BIT*sizeof(readfrom))
  330.         {
  331.               /* die if we overflow readfrom's size as an fd_set */
  332.             fatal("Internal error - too many open files?\n");
  333.         }
  334.         pid = fork();
  335.         if (pid == -1)  {
  336.             fatal("Try again.\n");
  337.         }
  338.         if (pid) {
  339.                 /* parent */
  340.             int one = 1;
  341.             close(0);
  342.             close(1); 
  343.             close(2);
  344.             close(f);
  345.             close(pv[1]);
  346.             readfrom = (1<<s) | (1<<pv[0]);
  347.             ioctl(pv[1], FIONBIO, (char *)&one);
  348.             /* should set s nbio! */
  349.             do {
  350.                 ready = readfrom;
  351.                 select(16, (fd_set *)&ready, NULL, NULL, NULL);
  352.                 if (ready & (1<<s)) {
  353.                     if (read(s, &sig, 1) <= 0)
  354.                         readfrom &= ~(1<<s);
  355.                     else
  356.                         killpg(pid, sig);
  357.                 }
  358.                 if (ready & (1<<pv[0])) {
  359.                     cc = read(pv[0], buf, sizeof(buf));
  360.                     if (cc <= 0) {
  361.                         shutdown(s, 1+1);
  362.                         readfrom &= ~(1<<pv[0]);
  363.                     } 
  364.                     else write(s, buf, cc);
  365.                 }
  366.             } while (readfrom);
  367.             exit(0);
  368.         }
  369.         /* child */
  370.         setpgrp();
  371.         close(s); 
  372.         close(pv[0]);
  373.         dup2(pv[1], 2);
  374.     }
  375.     if (*pwd->pw_shell == 0) {
  376.         /* Shouldn't we deny access? */
  377.         pwd->pw_shell = _PATH_BSHELL;
  378.     }
  379.     /* shouldn't we check /etc/shells? */
  380.  
  381.     if (f > 2) close(f);
  382.  
  383.     setgid(pwd->pw_gid);
  384.     initgroups(pwd->pw_name, pwd->pw_gid);
  385.     setuid(pwd->pw_uid);
  386.  
  387.     strcat(path, _PATH_DEFPATH);
  388.     myenviron = envinit;
  389.     strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
  390.     strncat(shell, pwd->pw_shell, sizeof(shell)-7);
  391.     strncat(username, pwd->pw_name, sizeof(username)-6);
  392.     cp = strrchr(pwd->pw_shell, '/');
  393.     if (cp)    cp++;
  394.     else cp = pwd->pw_shell;
  395.  
  396.     execle(pwd->pw_shell, cp, "-c", cmdbuf, 0, myenviron);
  397.     perror(pwd->pw_shell);
  398.     exit(1);
  399. }
  400.  
  401. static void
  402. fatal(const char *msg)
  403. {
  404.     char x = 1;
  405.     write(2, &x, 1);
  406.     write(2, msg, strlen(msg));
  407.     exit(1);
  408. }
  409.  
  410. static void
  411. getstr(char *buf, int cnt, const char *err)
  412. {
  413.     char c;
  414.  
  415.     do {
  416.         if (read(0, &c, 1) != 1)
  417.             exit(1);
  418.         *buf++ = c;
  419.         if (--cnt <= 0) {
  420.             fatal(err);
  421.         }
  422.     } while (c != 0);
  423. }
  424.